package top.yangguangmc.smart_scheduling.checks;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import top.yangguangmc.smart_scheduling.SessionManager;
import top.yangguangmc.smart_scheduling.SmartScheduling;
import top.yangguangmc.smart_scheduling.pojo.Employee;
import top.yangguangmc.smart_scheduling.pojo.Shift;
import top.yangguangmc.smart_scheduling.utils.Utils;

import javax.swing.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static top.yangguangmc.smart_scheduling.checks.TableProblemDomain.CELL;
import static top.yangguangmc.smart_scheduling.checks.TableProblemDomain.ROW;
import static top.yangguangmc.smart_scheduling.checks.TableProblemType.*;

public class ChecksManager {
    private final Logger logger = LogManager.getLogger();
    private final SmartScheduling.ScheduleTable table;
    private final SessionManager sessionManager;
    private final JTextArea outputArea;
    private final Set<TableProblem> problems;

    public ChecksManager(SmartScheduling.ScheduleTable table, SessionManager sessionManager, JTextArea outputArea) {
        this.table = table;
        this.sessionManager = sessionManager;
        this.outputArea = outputArea;
        problems = new HashSet<>();
    }

    public void scanProblems() {
        //1：日期时间格式
        Object cellDate = table.getValueAt(0, 3);
        if (!Utils.isNullOrEmpty(cellDate)) {
            try {
                String s = cellDate.toString().trim().replaceAll("[-/年月]", ".");
                s = s.replaceAll("日", "");
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
                SimpleDateFormat sdf2 = new SimpleDateFormat("M.d");
                Date date = sdf.parse(s);   //如果格式错误，程序流会终止与此，转到catch块
                Calendar c = Calendar.getInstance();
                c.setTime(date);
                setTableValue("星期" + parseDateToWeek(c), 1, 3);
                for (int i = 4; i <= 9; i++) {
                    c.roll(Calendar.DAY_OF_YEAR, 1);
                    setTableValue(sdf2.format(c.getTime()), 0, i);
                    setTableValue("星期" + parseDateToWeek(c), 1, i);
                }
//                logger.info("Successfully formatted date string from " + sdf.format(date) + ".");
                removeProblem(0, 3);
            } catch (ParseException ex) {
                String msg = "“" + cellDate + "”不是合法的日期格式！";
                addProblem(INVALID_INPUT, msg, 0, 3, CELL);
                SmartScheduling.showErrDialog(SmartScheduling.getInstance(), "“" + cellDate + "”不是合法的日期格式！" +
                        "\n<日期>单元格的内容必须满足“年份.月份.日期”的格式。\n如：“2024.2.6”、“2024年2月6日”、“2024-2-6”");
            }
        } else {
            String msg = "起始日期未设置。";
            addProblem(NOT_ENOUGH_INFO, msg, 0, 3, CELL);
        }

        //2：员工
        for (int row = 2; row < table.getRowCount(); row++) {
            for (int column = 1; column < 3; column++) {
                Object obj = table.getValueAt(row, column);
                if (!Utils.isNullOrEmpty(obj)) {
                    if (column == 1) {  //如果是“员工名”那列
                        Employee employee = sessionManager.getEmployee(obj.toString());
                        if (employee == null) {
                            addProblem(UNKNOWN_SYMBOL, "无法解析员工名：“" + obj + "”！", row, column, ROW);
                        } else {
                            Object obj2 = table.getValueAt(row, 2);
                            if (!Utils.isNullOrEmpty(obj2)) {
                                try {
                                    int id2 = Integer.parseInt(obj2.toString());
                                    Employee employee2 = sessionManager.getEmployee(id2);
                                    if (employee2 == null) {
                                        addProblem(UNKNOWN_SYMBOL, "无法解析员工工号：" + id2 + "！", row, column, ROW);
                                    } else if (!employee.equals(employee2)) {
                                        addProblem(MISMATCHED_INFO, "员工" + obj + "与其id不匹配！", row, column, ROW);
                                    } else {
                                        removeProblem(row, column);
                                    }
                                } catch (NumberFormatException ex) {
                                    addProblem(INVALID_INPUT, "员工工号：“" + obj2 + "”不是合法的正整数！", row, column, ROW);
                                }
                            } else {
                                addProblem(NOT_ENOUGH_INFO, "“" + obj + "”对应的工号未填写。应该为：" + employee.getId(), row, column, ROW);
                            }
                        }
                    } else {    //否则就一定是“工号”那列
                        try {
                            int id = Integer.parseInt(obj.toString());
                            Employee employee = sessionManager.getEmployee(id);
                            if (employee == null) {
                                addProblem(INVALID_INPUT, "无法解析员工工号：" + id + "！", row, column, ROW);
                            } else {
                                Object obj2 = table.getValueAt(row, 1);
                                if (!Utils.isNullOrEmpty(obj2)) {
                                    Employee employee2 = sessionManager.getEmployee(obj2.toString());
                                    if (employee2 == null) {
                                        addProblem(UNKNOWN_SYMBOL, "无法解析员工名：“" + obj2 + "”！", row, column, ROW);
                                    } else if (!employee.equals(employee2)) {
                                        addProblem(MISMATCHED_INFO, "员工" + obj2 + "与其id不匹配！", row, column, ROW);
                                    } else {
                                        removeProblem(row, column);
                                    }
                                } else {
                                    addProblem(NOT_ENOUGH_INFO, "员工工号" + id + "对应的员工名未填写。应该为：“" + employee.getName() + "”", row, column, ROW);
                                }
                            }
                        } catch (NumberFormatException ex) {
                            addProblem(INVALID_INPUT, "员工工号：“" + obj + "”不是合法的正整数！", row, column, ROW);
                        }
                    }
                }
            }
        }

        //3：班次
        for (int row = 2; row < table.getRowCount(); row++) {
            for (int column = 3; column < table.getColumnCount(); column++) {
                Object obj = table.getValueAt(row, column);
                if (!Utils.isNullOrEmpty(obj)) {
                    Shift shift = sessionManager.getShift(obj.toString());
                    if (shift == null) {
                        addProblem(UNKNOWN_SYMBOL, "无法解析班次名：“" + obj + "”！", row, column, CELL);
                    } else {
                        removeProblem(row, column);
                    }
                }
            }
        }
        //4：高级内容
        //4.1：检查一天只能是否有班次重复
        

    }

    public void addProblem(TableProblemType type, String str, int atX, int atY, TableProblemDomain domain) {
        problems.remove(new TableProblem(type, str, atX, atY, domain));
        problems.add(new TableProblem(type, str, atX, atY, domain));
        logger.warn("[表格错误] " + str + " 坐标：(" + atX + ", " + atY + ")");
        updateOutput();
    }

    public void removeProblem(int atX, int atY) {
        for (TableProblem error : problems) {
            if (error.getCellX() == atX && error.getCellY() == atY) {
                if (problems.remove(error)) {
                    updateOutput();
                    return;
                }
            }
        }
        updateOutput();
    }

    public void updateOutput() {
        StringBuilder sb = new StringBuilder();
        List<TableProblem> list = new ArrayList<>(problems);
        list.sort(Comparator.comparing(TableProblem::getMessage));
        for (TableProblem error : list) {
            sb.append("[").append(table.getColumnName(error.getCellY())).append(error.getCellX() - 1).append("] ");
            sb.append(error);
            sb.append("\n");
        }
        outputArea.setText(sb.toString());
    }

    private void setTableValue(Object aValue, int row, int column) {
        table.setProgrammedUpdate(true);
        table.setValueAt(aValue, row, column);
    }

    @NotNull
    public static String parseDateToWeek(@NotNull Calendar c) {
        int week = c.get(Calendar.DAY_OF_WEEK) - 1;
        if (week == 0) week = 7;
        switch (week) {
            case 1:
                return "一";
            case 2:
                return "二";
            case 3:
                return "三";
            case 4:
                return "四";
            case 5:
                return "五";
            case 6:
                return "六";
            case 7:
                return "日";
            default:
                throw new IllegalStateException("Switch week integer returned not between 1 to 7. This cannot happen!");
        }
    }

}
